package com.pb.wkflow.core.service;

import com.alibaba.fastjson.JSON;
import com.pb.wkflow.api.exception.ApprovalException;
import com.pb.wkflow.core.camunda.bpmn.instance.ExternalInterface;
import com.pb.wkflow.core.utils.RestTemplateUtil;
import com.pb.wkflow.core.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.camunda.bpm.engine.delegate.DelegateExecution;
import org.camunda.bpm.engine.delegate.JavaDelegate;
import org.camunda.bpm.engine.impl.persistence.entity.ExecutionEntity;

import java.util.*;

/**
 * 服务节点默认远程接口
 * @author 苗益辉
 * @date 2022/5/24 16:20
 */
@Slf4j
public class IHttpServiceTaskService implements JavaDelegate {

    private static List<String> HTTP_OK = null;
    private static List<String> HTTP_RESULT_CODE = null;
    private String VARIABLES = "variables";

    //返回成功结果code
    static {
        HTTP_OK = new ArrayList<>();
        HTTP_OK.add("200");
        HTTP_OK.add("000000");
    }

    //返回成功结果参数
    static {
        HTTP_RESULT_CODE = new ArrayList<>();
        HTTP_RESULT_CODE.add("code");
        HTTP_RESULT_CODE.add("errorCode");
    }

    @Override
    public void execute(DelegateExecution execution) {
        String externalInterface = execution.getBpmnModelElementInstance().getExtensionElements()
                .getElementsQuery().filterByType(ExternalInterface.class).singleResult().getTextContent();
        if(StringUtils.isBlank(externalInterface)) {
            throw new ApprovalException("服务节点需要配置远程接口");
        }
        Map<String, Object> paramsMap = new HashMap<>(2);
        addFields(execution, paramsMap);
        Map result;
        try{
            log.info("before call serviceTask params is : {}",paramsMap);
            String stringJson = JSON.toJSONString(paramsMap);
            String resultStr = RestTemplateUtil.post(externalInterface, stringJson);
            result = JSON.parseObject(resultStr, Map.class);
            String code = getCode(result);
            if(!HTTP_OK.contains(code)) {
                throw new ApprovalException("远程接口返回信息异常");
            }
        }catch (Exception e) {
            throw new ApprovalException("远程服务调用失败： "+ e);
        }
        execution.setVariables(getVariables(result, execution.getVariables()));
    }

    private void addFields(DelegateExecution execution, Map<String, Object> paramsMap) {
        ExecutionEntity entity = (ExecutionEntity) execution;
        //任务id
        paramsMap.put("id", execution.getId());
        //流程实例id
        paramsMap.put("processInstanceId",execution.getProcessInstanceId());
        //流程定义id
        paramsMap.put("processDefinitionId", execution.getProcessDefinitionId());
        //流程定义key
        paramsMap.put("processDefinitionKey", entity.getProcessDefinition().getKey());
        //流程定义名称
        paramsMap.put("processDefinitionName", entity.getProcessDefinition().getName());
        //流程部署id
        paramsMap.put("deploymentId", entity.getProcessDefinition().getDeploymentId());
        //流程部署版本
        paramsMap.put("processDefinitionVersion", entity.getProcessDefinition().getVersion());
        //流程发布租户
        paramsMap.put("tenantId", execution.getTenantId());
        //任务节点id
        paramsMap.put("activityId", execution.getCurrentActivityId().split("#")[0]);
        //任务节点名称
        paramsMap.put("activityName", execution.getCurrentActivityName());
        //任务流程变量
        paramsMap.put("variables", entity.getVariables());
    }

    /**
     * 返回信息中获取 HTTP_RESULT_STATUS 或 HTTP_RESULT_CODE 作为接口返回状态
     * @param result 接口返回信息
     * @return 接口返回状态
     */
    private String getCode(Map result) {
        for(String code : HTTP_RESULT_CODE) {
            if(result.containsKey(code)) {
                Object number = result.get(code);
                return number instanceof String ? (String) number :String.valueOf(number);
            }
        }
        return "-1";
    }

    /**
     * 获取接口返回结果
     * @param result 接口返回信息
     * @return 流程变量
     */
    private Map<String, Object> getVariables(Map result) {
        if(!result.containsKey(VARIABLES)) {
            return Collections.emptyMap();
        }
        Object map = result.get(VARIABLES);
        if(map instanceof Map) {
            return (Map<String, Object>) map;
        }
        try{
            return (Map<String, Object>) map;
        }catch (Exception e) {
            throw new ApprovalException("远程接口获取流程变量失败");
        }
    }

    /**
     * 获取接口返回结果
     * @param result 接口返回信息
     * @param variables 流程变量
     * @return 流程变量
     */
    private Map<String, Object> getVariables(Map result, Map<String, Object> variables) {
        Map<String, Object> newVariables = getVariables(result);
        for(String key : newVariables.keySet()) {
            variables.put(key, newVariables.get(key));
        }
        return variables;
    }
}